package com.smart.manager.task;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.smart.common.annotation.TaskBean;
import com.smart.common.annotation.TaskMethod;
import com.smart.common.cache.CacheService;
import com.smart.common.entities.domain.TaskResult;
import com.smart.manager.product.entities.assembler.CameraBody;
import com.smart.manager.product.entities.enums.CameraDirection;
import com.smart.manager.product.entities.enums.CameraStatus;
import com.smart.manager.product.entities.models.BasicCameraDetail;
import com.smart.manager.product.entities.models.query.QBasicCameraDetail;
import com.smart.manager.system.repository.ConfigRepository;
import io.ebean.DB;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 获取摄像头
 *
 * @author leo
 * @date 2023/09/011
 */
@Log4j2
@Component
@TaskBean
@RequiredArgsConstructor
public class CameraDetailTask {

    private final CacheService cacheService;
    private final ConfigRepository configRepository;

    /**
     * 同步摄像头地址
     */
    private final static String synchronous = "https://open.ys7.com/api/lapp/camera/list";

    /**
     * 同步萤石云摄像头
     *
     * @return {@link TaskResult}
     */
    @TaskMethod(title = "同步萤石云摄像头通道")
    public synchronized TaskResult earTagData() {
        String token = upToken();
        log.warn("TaskResultToken = {}" ,token );
        //开始更新token
        cacheService.getCameraTokenCache().put("accessToken", token);
        List<CameraBody> di = renewal(new ArrayList<>(), 0, token);
        try {
            if (CollUtil.isNotEmpty(di)) {
                List<BasicCameraDetail> rfid = new QBasicCameraDetail().findList();
                String date = OldAndNewUpdates(di, rfid);
                log.warn(di);
                return new TaskResult(true, date);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new TaskResult(false, "更新失败:" + e.getMessage());
        }
        return new TaskResult(false, "更新失败");
    }

    /**
     * 递归请求数据
     *
     * @return {@link List}<{@link CameraBody}>
     */
    public List<CameraBody> renewal(List<CameraBody> cameraList, int pageStart, String token) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("accessToken", token);
        map.put("pageStart", pageStart);
        map.put("pageSize", 50);  //API 每次请求做多分页10条
        HttpResponse execute = HttpRequest.post(synchronous).form(map).execute();
        JSONObject object = new JSONObject(execute.body());
        if (!object.get("code").equals("200")) {
            //结束 请求异常
            return null;
        }
        JSONObject page = new JSONObject(object.get("page"));
        Object data = object.get("data");
        List<CameraBody> cameras = JSONUtil.parseArray(data).toList(CameraBody.class);
        cameraList.addAll(cameras);
        if (!Objects.requireNonNull(page).getInt("total").equals(0)) {
            if (!(cameraList.size() == page.getInt("total"))) {
                renewal(cameraList, ++pageStart, token);
            }
        }
        return cameraList;
    }

    /**
     * 更新token
     *
     * @return {@link String}
     */
    public String upToken() {
        com.alibaba.fastjson2.JSONObject camera = configRepository.readCache("Camera");
        HashMap<String, Object> map = new HashMap<>();
        map.put("appKey", camera.get("appKey"));
        map.put("appSecret", camera.get("appSecret"));
        HttpResponse execute = HttpRequest.post("https://open.ys7.com/api/lapp/token/get").form(map).execute();
        JSONObject object = new JSONObject(execute.body());
        if (!Objects.equals(object.get("code"), "200")) {
            throw new RuntimeException(ObjectUtil.isNotEmpty(object.get("msg")) ? (String) object.get("msg") : "请求token接口异常");
        }
        Object data = object.get("data");
        Object token = new JSONObject(data).get("accessToken");
        return (String) token;
    }

    public static LocalDateTime time = LocalDateTime.now();

    /**
     * @param newly 新
     * @param old   旧
     */
    public String OldAndNewUpdates(List<CameraBody> newly, List<BasicCameraDetail> old) {


        ArrayList<BasicCameraDetail> add = new ArrayList<>();
        ArrayList<BasicCameraDetail> renewal = new ArrayList<>();
        // 数据库数据转body
        List<CameraBody> oldList = old.stream().map(x -> {
            CameraBody copied = BeanUtil.copyProperties(x, CameraBody.class);
            copied.setId(x.getPassageId());
            return copied;
        }).collect(Collectors.toList());

        Set<String> newId = newly.stream().map(CameraBody::getId).collect(Collectors.toSet());
        Set<String> oldId = old.stream().map(BasicCameraDetail::getPassageId).collect(Collectors.toSet());

//        List<BasicCameraDetail> collect = old.stream().filter(x -> CollUtil.subtract(oldId, newId).contains(x.getPassageId())).collect(Collectors.toList());

        //新增的数据
        List<CameraBody> collected = newly.stream().filter(x -> CollUtil.subtract(newId, oldId).contains(x.getId())).collect(Collectors.toList());
        collected.forEach(x -> {
            add.add(padding(x));
        });


        //修改的数据
        List<CameraBody> updateList = newly.stream().filter(x -> CollUtil.intersectionDistinct(newId, oldId).contains(x.getId())).collect(Collectors.toList());
        updateList.forEach(x -> {
            if (!CollUtil.contains(oldList,x)) {
                //不相同则更新
                renewal.add(padding(x));
            }
        });

        Opt.ofBlankAble(add).ifPresent(x->{
            x.forEach(c->{
                c.setCameraDirection(CameraDirection.UNKNOWN).setCameraStatus(CameraStatus.NOT_BOUND);
            });
            DB.insertAll(add);
        });
        HashMap<String, BasicCameraDetail> map = new HashMap<>();
        old.forEach(x->{
            map.put(x.getPassageId(),x);
        });
        Opt.ofBlankAble(renewal).ifPresent(x->{
            x.forEach(c->{
                BasicCameraDetail detail = map.get(c.getPassageId());
                //TODO: 可拓展 加入字段
                c.setCameraStatus(detail.getCameraStatus());
                c.setCameraDirection(detail.getCameraDirection());
                c.setId(detail.getId());
            });
            DB.updateAll(x);
        });
        return  "摄像头更新：新增:" + add.size() + "条,更新:" + renewal.size() + "条";
    }


    public BasicCameraDetail padding(CameraBody body) {
        return new BasicCameraDetail()
                .setPassageId(body.getId())
                .setStatus(body.getStatus())
                .setChannelNo(body.getChannelNo())
                .setChannelName(body.getChannelName())
                .setDeviceSerial(body.getDeviceSerial())
                .setIsEncrypt(body.getIsEncrypt())
                .setVideoLevel(body.getVideoLevel()).
                setAddTime(time);
    }


//    /**
//     * 更新数据
//     *
//     * @param newly
//     * @param old
//     * @param original
//     * @return {@link String}
//     * @throws Exception
//     */
//    public String upToDate(List<CameraBody> newly, List<CameraBody> old, List<BasicCameraDetail> original) throws Exception {
//        LocalDateTime time = LocalDateTime.now();
//        List<BasicCameraDetail> update = new ArrayList<>();
//        List<BasicCameraDetail> add = new ArrayList<>();
//        List<BasicCameraDetail> del = new ArrayList<>();
//        Set<String> cNewly = newly.stream().map(CameraBody::getId).collect(Collectors.toSet());
//        Set<String> cOld = old.stream().map(CameraBody::getId).collect(Collectors.toSet());
//        //离线的数据
//        old.stream().filter(x -> CollUtil.subtract(cOld, cNewly).contains(x.getId())).collect(Collectors.toList()).forEach(x -> old.forEach(c -> {
//            if (!c.equals(x)) {
//                for (BasicCameraDetail v : original) {
//                    if (v.getId().equals(c.getId())) {
//                        BeanUtil.copyProperties(c, v);
//                        c.setId(v.getPassageId());
//                        del.add(v);
//                    }
//                }
//            }
//        }));
//        //新增的数据
//        newly.stream().filter(x -> CollUtil.subtract(cNewly, cOld).contains(x.getId())).collect(Collectors.toList()).forEach(rfid -> {
//            Opt.ofBlankAble(BeanUtil.copyProperties(rfid, BasicCameraDetail.class)).ifPresent(c -> {
//                c.setAddTime(time);  //设置新建时间
//                c.setPassageId(rfid.getId());  //设置通道id
//                c.setId(null);
//                add.add(c);
//            });
//        });
//        //修改数据
//        List<CameraBody> updateList = newly.stream().filter(x -> CollUtil.intersectionDistinct(cNewly, cOld).contains(x.getId())).collect(Collectors.toList());
//        for (CameraBody x : updateList) {
//            CameraBody basic = null;
//            for (CameraBody c : old) {
//                if (c.getId().equals(x.getId())) {
//                    basic = c;
//                    break;
//                }
//            }
//            if (basic != null && !ObjectUtil.equals(basic, x)) {
//                CameraBody reqRfidEar = updateList.get(old.indexOf(basic));
//                for (BasicCameraDetail v : original) {
//                    if (v.getId().equals(reqRfidEar.getId())) {
//                        BeanUtil.copyProperties(reqRfidEar, v);
//                        v.setPassageId(x.getId());
//                        v.setId(null);
//                        update.add(v);
//                    }
//                }
//            }
//        }
//        log.warn("摄像头数据更新：修改的数据 有 = {} 条", update.size());
//        log.warn("摄像头数据更新：新增的数据 有 = {} 条", add.size());
//        log.warn("摄像头数据更新：被移出的数据 有 = {} 条", del.size());
//        Opt.ofBlankAble(add).ifPresent(DB::insertAll);
//        Opt.ofBlankAble(update).ifPresent(DB::updateAll);
//        Opt.ofBlankAble(del).ifPresent(DB::updateAll);
//        return "摄像头更新：新增:" + add.size() + "条,更新:" + update.size() + "条,移出:" + del.size() + "条";
//    }
}
